package com.lin.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.sql.DataSource;
import java.io.IOException;

/**
 * @author lin
 */
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private DataSource dataSource;

    /**
     * 设置认证方式
     *
     * @param auth
     * @throws Exception
     */
    @Override
    protected void configure ( AuthenticationManagerBuilder auth ) throws Exception {
        //JDBC认证方式
        //设置密码的加密方式
//        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();


        //写SQL
        //查询username/password/validate
        String userSql = "select username,password,valid from t_user where username=?";
        //查询权限 :username / authority
        String authoritysql = "select a.username,b.authority " +
                "from t_user a,t_authority b,t_user_authority c " +
                "where a.id=c.user_id and b.id=c.authority_id and a.username=?";
        //设置认证方式:
        auth.jdbcAuthentication().passwordEncoder(bCryptPasswordEncoder)
                .dataSource(dataSource)
                .usersByUsernameQuery(userSql)
                .authoritiesByUsernameQuery(authoritysql);

    }

    /**
     * 设置访问控制
     *
     * @param http
     * @throws Exception
     */
    @Override
    protected void configure ( HttpSecurity http ) throws Exception {
        //1 自定访问控制:
        // 静态资源直接放行/首页/详情页/登录   -->直接放行
        // 后台页面 -->必须是管理员权限admin
        // 其它:需要认证
        http.authorizeRequests()
                .antMatchers("/", "/articleDetail/**", "/page/**", "/toLogin").permitAll()
                .antMatchers("/article_img/**", "/assets/**", "/back/**", "/user/**").permitAll()
                .antMatchers("/admin/**").hasRole("admin")
                .anyRequest()
                .authenticated();
        /**
         * 2 设置登录访问控制
         */
        http.formLogin()
                ///写跳转到登录页的路径
                .loginPage("/toLogin")
                .loginProcessingUrl("/login")
                .usernameParameter("username")
                .passwordParameter("password")
                .successHandler(new AuthenticationSuccessHandler() {
                    @Override
                    public void onAuthenticationSuccess ( HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication ) throws IOException, ServletException {
                        //登录成功处理:
                        //回到详情页/回到首页/进入后台管理页面
                        httpServletResponse.sendRedirect("/");
                    }
                })
                .failureHandler(new AuthenticationFailureHandler() {
                    @Override
                    public void onAuthenticationFailure ( HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e ) throws IOException, ServletException {
                        //回到登录页继续登录
                        httpServletRequest.getRequestDispatcher("/toLogin?error").forward(httpServletRequest, httpServletResponse);
                    }
                });
        //3 退出控制
        http.logout()
                .logoutUrl("/logout")
                .logoutSuccessUrl("/");

        //设置403页面
        http.exceptionHandling().accessDeniedHandler(new AccessDeniedHandler() {
            @Override
            public void handle ( HttpServletRequest Request, HttpServletResponse Response, AccessDeniedException e ) throws IOException, ServletException {
                //权限访问异常,指定错误页面
                Request.getRequestDispatcher("/errPage/comm/error_403").forward(Request, Response);
            }
        });
    }


}
